#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdbool.h>

#define WIDTH 60
#define HEIGHT 30
#define CELL_SIZE 2
#define MAX_LENGTH 100

enum Directions { UP, RIGHT, DOWN, LEFT };

HANDLE hOut;
COORD food;
int score = 0, hiscore = 0;
bool gameover = false;
int currentDir = RIGHT;
int newDir = RIGHT;

struct {
    COORD body[MAX_LENGTH];
    int length;
} snake;

/* 初始化控制台 */
void InitConsole() {
    hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO cursor = { 1, 0 };
    SetConsoleCursorInfo(hOut, &cursor);
    SetConsoleTitleW(L"终极版贪吃蛇");
    system("mode con cols=80 lines=35");
}

/* 生成新食物 */
void GenerateFood() {
    bool valid;
    do {
        valid = true;
        food.X = (rand() % (WIDTH/CELL_SIZE - 4) + 2) * CELL_SIZE;
        food.Y = rand() % (HEIGHT - 4) + 2;

        for (int i = 0; i < snake.length; i++) {
            if (food.X == snake.body[i].X && 
                food.Y == snake.body[i].Y) {
                valid = false;
                break;
            }
        }
    } while (!valid);
}

/* 初始化游戏数据 */
void NewGame() {
    // 初始化蛇
    snake.length = 3;
    for (int i = 0; i < snake.length; i++) {
        snake.body[i].X = 20 - i * CELL_SIZE;
        snake.body[i].Y = 15;
    }
    currentDir = RIGHT;
    newDir = RIGHT;
    score = 0;

    // 读取最高分
    FILE* fp = fopen("hiscore.dat", "r");
    if (fp) {
        fscanf(fp, "%d", &hiscore);
        fclose(fp);
    }

    GenerateFood();
}

/* 绘制游戏边框 */
void DrawBorder() {
    SetConsoleTextAttribute(hOut, 0x09); // 蓝色边框
    for (int x = 0; x < WIDTH; x += CELL_SIZE) {
        SetConsoleCursorPosition(hOut, (COORD){x, 0});
        printf("■");
        SetConsoleCursorPosition(hOut, (COORD){x, HEIGHT-1});
        printf("■");
    }
    for (int y = 1; y < HEIGHT-1; y++) {
        SetConsoleCursorPosition(hOut, (COORD){0, y});
        printf("■");
        SetConsoleCursorPosition(hOut, (COORD){WIDTH-CELL_SIZE, y});
        printf("■");
    }
}

/* 绘制游戏元素 */
void DrawGame() {
    system("cls");
    DrawBorder();

    // 绘制蛇身
    SetConsoleTextAttribute(hOut, 0x0A); // 绿色
    for (int i = 0; i < snake.length; i++) {
        SetConsoleCursorPosition(hOut, snake.body[i]);
        printf(i == 0 ? "◎" : "■");
    }

    // 绘制食物
    SetConsoleTextAttribute(hOut, 0x0C); // 红色
    SetConsoleCursorPosition(hOut, food);
    printf("●");

    // 显示分数
    SetConsoleTextAttribute(hOut, 0x07); // 白色
    SetConsoleCursorPosition(hOut, (COORD){WIDTH+2, 5});
    printf("得分: %d", score);
    SetConsoleCursorPosition(hOut, (COORD){WIDTH+2, 7});
    printf("记录: %d", hiscore);
}

/* 移动蛇身 */
void MoveSnake() {
    // 移动身体（从尾部开始更新）
    for (int i = snake.length-1; i > 0; i--) {
        snake.body[i] = snake.body[i-1];
    }

    // 移动头部
    switch (currentDir) {
        case UP:    snake.body[0].Y--; break;
        case DOWN:  snake.body[0].Y++; break;
        case LEFT:  snake.body[0].X -= CELL_SIZE; break;
        case RIGHT: snake.body[0].X += CELL_SIZE; break;
    }

    // 吃到食物处理
    if (snake.body[0].X == food.X && snake.body[0].Y == food.Y) {
        if (snake.length < MAX_LENGTH) {
            snake.length++;
        }
        score += 10;
        GenerateFood();
    }
}

/* 碰撞检测 */
bool CheckCollisions() {
    // 墙碰撞检测
    if (snake.body[0].X < CELL_SIZE || 
        snake.body[0].X >= WIDTH - CELL_SIZE ||
        snake.body[0].Y < 1 || 
        snake.body[0].Y >= HEIGHT - 1) {
        return true;
    }

    // 自噬检测（跳过前3节）
    for (int i = 3; i < snake.length; i++) {
        if (snake.body[0].X == snake.body[i].X &&
            snake.body[0].Y == snake.body[i].Y) {
            return true;
        }
    }
    return false;
}

/* 处理输入 */
void ProcessInput() {
    if (_kbhit()) {
        int ch = _getch();
        if (ch == 0xE0) { // 方向键
            ch = _getch();
            switch (ch) {
                case 72: if (currentDir != DOWN) newDir = UP; break;
                case 80: if (currentDir != UP) newDir = DOWN; break;
                case 75: if (currentDir != RIGHT) newDir = LEFT; break;
                case 77: if (currentDir != LEFT) newDir = RIGHT; break;
            }
        }
        else if (ch == 27) gameover = true; // ESC退出
    }
}

/* 欢迎界面 */
void ShowWelcome() {
    system("cls");
    printf("\n\n\t\t 欢迎来到贪吃蛇！ \n");
    printf("\n\t1. 开始游戏");
    printf("\n\t2. 游戏说明");
    printf("\n\t3. 退出游戏\n");

    while (true) {
        if (_kbhit()) {
            int ch = _getch();
            switch (ch) {
                case '1': return;
                case '2':
                    system("cls");
                    printf("\n\t游戏规则：");
                    printf("\n\t- 使用方向键控制移动");
                    printf("\n\t- 吃红色食物（●）增长身体");
                    printf("\n\t- 避免碰撞墙壁和自身");
                    printf("\n\t- ESC键可随时退出");
                    printf("\n\n按任意键返回...");
                    _getch();
                    ShowWelcome();
                    return;
                case '3': exit(0);
            }
        }
        Sleep(100);
    }
}

/* 游戏结束界面 */
void GameOverScreen() {
    system("cls");
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(hOut, &csbi);
    int consoleWidth = csbi.srWindow.Right - csbi.srWindow.Left + 1;

    // 显示标题
    SetConsoleTextAttribute(hOut, 0x0C);
    COORD pos = {consoleWidth/2 - 8, 5};
    SetConsoleCursorPosition(hOut, pos);
    printf("=== 游戏结束 ===");

    // 分数信息
    pos.Y += 3;
    SetConsoleCursorPosition(hOut, pos);
    if(score > hiscore) {
        printf("创纪录啦！新纪录：%d分！", score);
        hiscore = score;
        FILE* fp = fopen("hiscore.dat", "w");
        if(fp) fprintf(fp, "%d", hiscore);
        fclose(fp);
        
        pos.Y += 2;
        SetConsoleCursorPosition(hOut, pos);
        printf("★★★★★ 最高分被你刷新啦，真棒！★★★★★");
    } else if(hiscore == 0) {
        printf("当前得分：%d（暂无历史记录）", score);
    } else {
        printf("继续努力吧~ 还差 %d 分破纪录", hiscore - score);
        pos.Y += 2;
        SetConsoleCursorPosition(hOut, pos);
        printf("本次得分：%d  历史最高：%d", score, hiscore);
    }

    // 操作选项
    pos.Y += 3;
    SetConsoleTextAttribute(hOut, 0x0E);
    SetConsoleCursorPosition(hOut, pos);
    printf("1. 重新挑战");
    pos.Y += 2;
    SetConsoleCursorPosition(hOut, pos);
    printf("2. 退出游戏");

    // 输入处理
    while(true) {
        pos.Y += 2;
        SetConsoleTextAttribute(hOut, 0x07);
        SetConsoleCursorPosition(hOut, pos);
        printf("请输入选择（1/2）: ");
        
        int ch = _getch();
        if(ch == '1') {
            gameover = false;
            NewGame();
            return;
        } else if(ch == '2') {
            exit(0);
        }
        
        // 错误处理
        SetConsoleTextAttribute(hOut, 0x0C);
        COORD errPos = {pos.X, pos.Y + 1};
        SetConsoleCursorPosition(hOut, errPos);
        printf("输入无效，请重新输入！");
        Sleep(800);
        SetConsoleCursorPosition(hOut, errPos);
        printf("                      ");
    }
}

/* 主函数 */
int main() {
    srand((unsigned)time(NULL));
    InitConsole();
    ShowWelcome();

    while (true) {
        NewGame();
        gameover = false;

        while (!gameover) {
            DrawGame();
            ProcessInput();
            currentDir = newDir;
            MoveSnake();
            
            if(CheckCollisions()) {
                gameover = true;
            }
            
            Sleep(150 - score); // 动态速度
        }

        GameOverScreen();
    }
    return 0;
}